#if !defined(FUNCTION_H)
#define FUNCTION_H

#define PI   3.1415926535897932385

# include <iostream>
#include <vector>
using namespace std;
# include "nr_c/nr.h"
# include "Tracker.h"
#include "molecule.h"

class Function
{
public :
	Function() { }	
	virtual ~Function() { }
	virtual double Value(double *X) = 0;
  virtual double Value(vector<double> &X) {return 0.0;}
  virtual double NormValue(double *X) {return 0.0;}
  virtual double NormValue(vector<double> &X) {return 0.0;}

  // returns the derivative in Derivative
  // was void but had to change to test derivative in test_function()
	virtual void   BuildDerivative(double *Input, double *Derivative) = 0;

  virtual double distanceFromGlobalMinimum(double *solution) 
  {
    //cout << "Not implemented yet!!!\n";
    return 1.0;
  }

	int NInput;  // number of degrees of freedom
  int nCall;
  int nMult;
  double dval;

  //Molecule *MyMolecule;

	Tracker Result;	


  // returns best solution (stored in tracker) in *solution and this function returns
  // the function value of this solution as a double. 
  virtual double BestSoFar(double *solution)
  {
    double x;

    Result.Best(x, solution);

    return (x);
  }

  virtual double BestSoFar()
  {
    double x;

    x = Result.getBestValue();

    return (x);
  }


	// to print out Input solution (not tracker solution) plus stuff relevant for HMC
  virtual void print_sol(double *Input, double ChiSq, char name[], int NAccept, int NTotal) {}

  // print out solution in Input (not tracker solution)
  virtual void print_sol(double *Input, double ChiSq, char name[]) {}

  // print out solution to stream
  virtual void print_sol(double *Input, double ChiSq, ofstream& append, string cifLabel = "default") {}

  // print out tracker solution
  virtual void print_sol(char filename[]) {}
  
  // return upper and lower parameter bounds for each parameter
  virtual void getUpperLowerBounds(vector<double>& lower, vector<double>& upper) { };
	
	// Return a random solution
	virtual void createRandomSol(double *TestInput) = 0;

	// Return a custom modified solution
  // E.g. by moving just the i'th coordinate of the solution
	virtual void customModifySol(double *TestInput, int i) = 0;

	// to set temperature for calculating derivative of in Likelihood

//	virtual void SetTempForDerivLikelihood(double t) = 0;
};

#endif
